Only show the mnemonic underline when pressing Alt
authorMatthias Clasen <mclasen@redhat.com>
Sun, 20 Dec 2009 08:04:52 +0000 (03:04 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 20 Dec 2009 08:11:05 +0000 (03:11 -0500)
...and show them in menus when navigating the menu with the keyboard.
This is similar to what other platforms do, and reduces visual clutter.
There is a setting to control this. Most of the work on this patch was
done by Thomas Wood. See bug 588554.

gtk/gtklabel.c
gtk/gtklabel.h
gtk/gtkmain.c
gtk/gtkmenu.c
gtk/gtkmenubar.c
gtk/gtkmenuitem.c
gtk/gtkmenushell.c
gtk/gtkmenushell.h
gtk/gtksettings.c
gtk/gtkwindow.c
gtk/gtkwindow.h

index 73fa93a35b3c28b928f4087a59edbcb3811c212d..475d84278b5a7b7ec55f1a809b7f86abce774aeb 100644 (file)
@@ -58,6 +58,8 @@ typedef struct
   gint wrap_width;
   gint width_chars;
   gint max_width_chars;
+
+  gboolean mnemonics_visible;
 } GtkLabelPrivate;
 
 /* Notes about the handling of links:
@@ -264,6 +266,9 @@ static void     gtk_label_buildable_custom_finished    (GtkBuildable     *builda
                                                        gpointer          user_data);
 
 
+static void connect_mnemonics_visible_notify    (GtkLabel   *label);
+
+
 /* For selectable labels: */
 static void gtk_label_move_cursor        (GtkLabel        *label,
                                          GtkMovementStep  step,
@@ -1037,6 +1042,8 @@ gtk_label_init (GtkLabel *label)
   label->mnemonic_widget = NULL;
   label->mnemonic_window = NULL;
 
+  priv->mnemonics_visible = TRUE;
+
   gtk_label_set_text (label, "");
 }
 
@@ -1486,7 +1493,9 @@ gtk_label_setup_mnemonic (GtkLabel *label,
     }
   
   if (label->mnemonic_keyval == GDK_VoidSymbol)
-    goto done;
+      goto done;
+
+  connect_mnemonics_visible_notify (GTK_LABEL (widget));
 
   toplevel = gtk_widget_get_toplevel (widget);
   if (GTK_WIDGET_TOPLEVEL (toplevel))
@@ -1564,6 +1573,65 @@ label_shortcut_setting_changed (GtkSettings *settings)
   g_list_free (list);
 }
 
+static void
+mnemonics_visible_apply (GtkWidget *widget,
+                         gboolean   mnemonics_visible)
+{
+  GtkLabel *label;
+  GtkLabelPrivate *priv;
+
+  label = GTK_LABEL (widget);
+
+  if (!label->use_underline)
+    return;
+
+  priv = GTK_LABEL_GET_PRIVATE (label);
+
+  mnemonics_visible = mnemonics_visible != FALSE;
+
+  if (priv->mnemonics_visible != mnemonics_visible)
+    {
+      priv->mnemonics_visible = mnemonics_visible;
+
+      gtk_label_recalculate (label);
+    }
+}
+
+static void
+label_mnemonics_visible_traverse_container (GtkWidget *widget,
+                                            gpointer   data)
+{
+  gboolean mnemonics_visible = GPOINTER_TO_INT (data);
+
+  _gtk_label_mnemonics_visible_apply_recursively (widget, mnemonics_visible);
+}
+
+void
+_gtk_label_mnemonics_visible_apply_recursively (GtkWidget *widget,
+                                                gboolean   mnemonics_visible)
+{
+  if (GTK_IS_LABEL (widget))
+    mnemonics_visible_apply (widget, mnemonics_visible);
+  else if (GTK_IS_CONTAINER (widget))
+    gtk_container_forall (GTK_CONTAINER (widget),
+                          label_mnemonics_visible_traverse_container,
+                          GINT_TO_POINTER (mnemonics_visible));
+}
+
+static void
+label_mnemonics_visible_changed (GtkWindow  *window,
+                                 GParamSpec *pspec,
+                                 gpointer    data)
+{
+  gboolean mnemonics_visible;
+
+  g_object_get (window, "mnemonics-visible", &mnemonics_visible, NULL);
+
+  gtk_container_forall (GTK_CONTAINER (window),
+                        label_mnemonics_visible_traverse_container,
+                        GINT_TO_POINTER (mnemonics_visible));
+}
+
 static void
 gtk_label_screen_changed (GtkWidget *widget,
                          GdkScreen *old_screen)
@@ -2420,6 +2488,7 @@ static void
 gtk_label_set_pattern_internal (GtkLabel    *label,
                                const gchar *pattern)
 {
+  GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
   PangoAttrList *attrs;
   gboolean enable_mnemonics;
 
@@ -2432,7 +2501,8 @@ gtk_label_set_pattern_internal (GtkLabel    *label,
                "gtk-enable-mnemonics", &enable_mnemonics,
                NULL);
 
-  if (enable_mnemonics && pattern)
+  if (enable_mnemonics && priv->mnemonics_visible && pattern &&
+      GTK_WIDGET_IS_SENSITIVE (label))
     attrs = gtk_label_pattern_to_attrs (label, pattern);
   else
     attrs = NULL;
@@ -4178,6 +4248,38 @@ gtk_label_button_release (GtkWidget      *widget,
   return TRUE;
 }
 
+static void
+connect_mnemonics_visible_notify (GtkLabel *label)
+{
+  GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
+  GtkWidget *toplevel;
+  gboolean connected;
+
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
+
+  if (!GTK_IS_WINDOW (toplevel))
+    return;
+
+  /* always set up this widgets initial value */
+  priv->mnemonics_visible =
+    gtk_window_get_mnemonics_visible (GTK_WINDOW (toplevel));
+
+  connected =
+    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (toplevel),
+                                        "gtk-label-mnemonics-visible-connected"));
+
+  if (!connected)
+    {
+      g_signal_connect (toplevel,
+                        "notify::mnemonics-visible",
+                        G_CALLBACK (label_mnemonics_visible_changed),
+                        label);
+      g_object_set_data (G_OBJECT (toplevel),
+                         "gtk-label-mnemonics-visible-connected",
+                         GINT_TO_POINTER (1));
+    }
+}
+
 static void
 drag_begin_cb (GtkWidget      *widget,
                GdkDragContext *context,
@@ -5707,7 +5809,7 @@ gtk_label_activate_current_link (GtkLabel *label)
           if (window &&
               window->default_widget != widget &&
               !(widget == window->focus_widget &&
-                (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
+                (!window->default_widget || !GTK_WIDGET_IS_SENSITIVE (window->default_widget))))
             gtk_window_activate_default (window);
         }
     }
index d44b142fadbf4c2a7ccfe7e09aabdfe90a5e37c2..88a9db7ddffbf199881f64f461f5ec2d1be79083 100644 (file)
@@ -197,6 +197,11 @@ guint gtk_label_parse_uline            (GtkLabel    *label,
 
 #endif /* GTK_DISABLE_DEPRECATED */
 
+/* private */
+
+void _gtk_label_mnemonics_visible_apply_recursively (GtkWidget *widget,
+                                                     gboolean   mnemonics_visible);
+
 G_END_DECLS
 
 #endif /* __GTK_LABEL_H__ */
index 581403b54160a49cdf56455fecec37d98dadb5b4..af03f3578e68d848df54f9abed55fdefbcd36ad7 100644 (file)
@@ -63,6 +63,8 @@
 #include "gtktooltip.h"
 #include "gtkdebug.h"
 #include "gtkalias.h"
+#include "gtkmenu.h"
+#include "gdk/gdkkeysyms.h"
 
 #include "gdk/gdkprivate.h" /* for GDK_WINDOW_DESTROYED */
 
@@ -1613,6 +1615,27 @@ gtk_main_do_event (GdkEvent *event)
          if (gtk_invoke_key_snoopers (grab_widget, event))
            break;
        }
+      /* catch alt press to enable auto-mnemonics */
+      if (event->key.keyval == GDK_Alt_L || event->key.keyval == GDK_Alt_R)
+        {
+          gboolean auto_mnemonics;
+
+          g_object_get (gtk_widget_get_settings (grab_widget),
+                        "gtk-auto-mnemonics", &auto_mnemonics, NULL);
+
+          if (auto_mnemonics)
+            {
+              gboolean mnemonics_visible;
+              GtkWidget *window;
+
+              mnemonics_visible = (event->type == GDK_KEY_PRESS);
+
+              window = gtk_widget_get_toplevel (grab_widget);
+
+              if (GTK_IS_WINDOW (window))
+                gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
+            }
+        }
       /* else fall through */
     case GDK_MOTION_NOTIFY:
     case GDK_BUTTON_RELEASE:
index e8813c9f0db35348687c6a60e92e0120e6c612e2..241ef413edad62d3935e477bd939e75a30ab616f 100644 (file)
@@ -1616,6 +1616,18 @@ gtk_menu_popup (GtkMenu              *menu,
   if (xgrab_shell == widget)
     popup_grab_on_window (widget->window, activate_time, grab_keyboard); /* Should always succeed */
   gtk_grab_add (GTK_WIDGET (menu));
+
+  if (parent_menu_shell)
+    {
+      gboolean keyboard_mode;
+
+      keyboard_mode = _gtk_menu_shell_get_keyboard_mode (GTK_MENU_SHELL (parent_menu_shell));
+      _gtk_menu_shell_set_keyboard_mode (menu_shell, keyboard_mode);
+    }
+  else if (menu_shell->button == 0) /* a keynav-activated context menu */
+    _gtk_menu_shell_set_keyboard_mode (menu_shell, TRUE);
+
+  _gtk_menu_shell_update_mnemonics (menu_shell);
 }
 
 void
index a54e456d1b284290398e19e69fdcde08d120f35e..3d2bbb513cb01b9999ab0e5f6724a76849aab226 100644 (file)
@@ -625,6 +625,7 @@ window_key_press_handler (GtkWidget   *widget,
            {
              GtkMenuShell *menu_shell = GTK_MENU_SHELL (menubars->data);
 
+              _gtk_menu_shell_set_keyboard_mode (menu_shell, TRUE);
              _gtk_menu_shell_activate (menu_shell);
              gtk_menu_shell_select_first (menu_shell, FALSE);
              
index 13db059bd4d233166aa6c9ae2d4324e98fcd0c24..1f3e1a96910430b99047a7db74fcf8720825b144 100644 (file)
@@ -1374,6 +1374,9 @@ static gboolean
 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
                                 gboolean   group_cycling)
 {
+  if (GTK_IS_MENU_SHELL (widget->parent))
+    _gtk_menu_shell_set_keyboard_mode (GTK_MENU_SHELL (widget->parent), TRUE);
+
   if (group_cycling &&
       widget->parent &&
       GTK_IS_MENU_SHELL (widget->parent) &&
index 910c760d56aa727b4bfa02ddb4d82311d1458a1c..4f7d82c8eacd6c864515677477078ad4f8965406 100644 (file)
@@ -30,6 +30,7 @@
 #include "gdk/gdkkeysyms.h"
 #include "gtkbindings.h"
 #include "gtkkeyhash.h"
+#include "gtklabel.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
 #include "gtkmenu.h"
@@ -773,6 +774,76 @@ gtk_menu_shell_button_release (GtkWidget      *widget,
   return TRUE;
 }
 
+void
+_gtk_menu_shell_set_keyboard_mode (GtkMenuShell *menu_shell,
+                                   gboolean      keyboard_mode)
+{
+  menu_shell->keyboard_mode = keyboard_mode;
+}
+
+gboolean
+_gtk_menu_shell_get_keyboard_mode (GtkMenuShell *menu_shell)
+{
+  return menu_shell->keyboard_mode;
+}
+
+void
+_gtk_menu_shell_update_mnemonics (GtkMenuShell *menu_shell)
+{
+  GtkMenuShell *target;
+  gboolean auto_mnemonics;
+  gboolean found;
+  gboolean mnemonics_visible;
+
+  g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
+                "gtk-auto-mnemonics", &auto_mnemonics, NULL);
+
+  if (!auto_mnemonics)
+    return;
+
+  target = menu_shell;
+  found = FALSE;
+  while (target)
+    {
+      /* The idea with keyboard mode is that once you start using
+       * the keyboard to navigate the menus, we show mnemonics
+       * until the menu navigation is over. To that end, we spread
+       * the keyboard mode upwards in the menu hierarchy here.
+       * Also see gtk_menu_popup, where we inherit it downwards.
+       */
+      if (menu_shell->keyboard_mode)
+        target->keyboard_mode = TRUE;
+
+      /* While navigating menus, the first parent menu with an active
+       * item is the one where mnemonics are effective, as can be seen
+       * in gtk_menu_shell_key_press below.
+       * We also show mnemonics in context menus. The grab condition is
+       * necessary to ensure we remove underlines from menu bars when
+       * dismissing menus.
+       */
+      mnemonics_visible = target->keyboard_mode &&
+                          ((target->active_menu_item && !found) ||
+                           (target == menu_shell &&
+                            !target->parent_menu_shell &&
+                            gtk_widget_has_grab (target)));
+
+      /* While menus are up, only show underlines inside the menubar,
+       * not in the entire window.
+       */
+      if (GTK_IS_MENU_BAR (target))
+        _gtk_label_mnemonics_visible_apply_recursively (GTK_WIDGET (target),
+                                                        mnemonics_visible);
+      else
+        gtk_window_set_mnemonics_visible (GTK_WINDOW (gtk_widget_get_toplevel (target)),
+                                          mnemonics_visible);
+
+      if (target->active_menu_item)
+        found = TRUE;
+
+      target = GTK_MENU_SHELL (target->parent_menu_shell);
+    }
+}
+
 static gint
 gtk_menu_shell_key_press (GtkWidget   *widget,
                          GdkEventKey *event)
@@ -780,9 +851,11 @@ gtk_menu_shell_key_press (GtkWidget   *widget,
   GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
   gboolean enable_mnemonics;
 
+  menu_shell->keyboard_mode = TRUE;
+
   if (!menu_shell->active_menu_item && menu_shell->parent_menu_shell)
     return gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent *)event);
-  
+
   if (gtk_bindings_activate_event (GTK_OBJECT (widget), event))
     return TRUE;
 
@@ -992,11 +1065,15 @@ gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell)
       if (menu_shell->have_xgrab)
        {
          GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (menu_shell));
-         
+
          menu_shell->have_xgrab = FALSE;
          gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
          gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
        }
+
+      menu_shell->keyboard_mode = FALSE;
+
+      _gtk_menu_shell_update_mnemonics (menu_shell);
     }
 }
 
@@ -1079,6 +1156,8 @@ gtk_menu_shell_real_select_item (GtkMenuShell *menu_shell,
                                  GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement);
   gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item));
 
+  _gtk_menu_shell_update_mnemonics (menu_shell);
+
   /* This allows the bizarre radio buttons-with-submenus-display-history
    * behavior
    */
@@ -1095,6 +1174,7 @@ gtk_menu_shell_deselect (GtkMenuShell *menu_shell)
     {
       gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item));
       menu_shell->active_menu_item = NULL;
+      _gtk_menu_shell_update_mnemonics (menu_shell);
     }
 }
 
@@ -1340,6 +1420,7 @@ gtk_real_menu_shell_move_current (GtkMenuShell         *menu_shell,
            * menu.
            */
           _gtk_menu_item_popdown_submenu (menu_shell->active_menu_item);
+          _gtk_menu_shell_update_mnemonics (menu_shell);
         }
       else if (parent_menu_shell)
        {
@@ -1347,6 +1428,7 @@ gtk_real_menu_shell_move_current (GtkMenuShell         *menu_shell,
             {
               /* close menu when returning from submenu. */
               _gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->parent_menu_item);
+              _gtk_menu_shell_update_mnemonics (parent_menu_shell);
               break;
             }
 
index e8281bcbb44717ad54d6c53e8844e1d5b6559e0b..614d3975f25f5397425e31a111cfbce8b9fcb52a 100644 (file)
@@ -65,6 +65,7 @@ struct _GtkMenuShell
   guint GSEAL (ignore_leave) : 1; /* unused */
   guint GSEAL (menu_flag) : 1;    /* unused */
   guint GSEAL (ignore_enter) : 1;
+  guint GSEAL (keyboard_mode) : 1;
 };
 
 struct _GtkMenuShellClass
@@ -130,6 +131,11 @@ gboolean gtk_menu_shell_get_take_focus (GtkMenuShell *menu_shell);
 void     gtk_menu_shell_set_take_focus (GtkMenuShell *menu_shell,
                                         gboolean      take_focus);
 
+void     _gtk_menu_shell_update_mnemonics  (GtkMenuShell *menu_shell);
+void     _gtk_menu_shell_set_keyboard_mode (GtkMenuShell *menu_shell,
+                                            gboolean      keyboard_mode);
+gboolean _gtk_menu_shell_get_keyboard_mode (GtkMenuShell *menu_shell);
+
 G_END_DECLS
 
 #endif /* __GTK_MENU_SHELL_H__ */
index 9e28fb9229d07ea5a845e6986259ec75073ff094..a7ca546a083874cc83f55596c1f8bac7c9032b7f 100644 (file)
@@ -124,7 +124,8 @@ enum {
   PROP_ENABLE_EVENT_SOUNDS,
   PROP_ENABLE_TOOLTIPS,
   PROP_TOOLBAR_STYLE,
-  PROP_TOOLBAR_ICON_SIZE
+  PROP_TOOLBAR_ICON_SIZE,
+  PROP_AUTO_MNEMONICS
 };
 
 
@@ -999,6 +1000,23 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                                                    GTK_PARAM_READWRITE),
                                              gtk_rc_property_parse_enum);
   g_assert (result == PROP_TOOLBAR_ICON_SIZE);
+
+  /**
+   * GtkSettings:gtk-auto-mnemonics:
+   *
+   * Whether mnemonics should be automatically shown and hidden when the user
+   * presses the mnemonic activator.
+   *
+   * Since: 2.20
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-auto-mnemonics",
+                                                                   P_("Auto Mnemonics"),
+                                                                   P_("Whether mnemonics should be automatically shown and hidden when the user presses the mnemonic activator."),
+                                                                   FALSE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_AUTO_MNEMONICS);
 }
 
 static void
index f01820d1fb19daefc402866a7e56eb993f2f47ae..f5ec59ff4082ecffe3785b6d38ec5dbf2046c623 100644 (file)
@@ -101,6 +101,8 @@ enum {
   /* Writeonly properties */
   PROP_STARTUP_ID,
   
+  PROP_MNEMONICS_VISIBLE,
+
   LAST_ARG
 };
 
@@ -185,6 +187,9 @@ struct _GtkWindowPrivate
   guint opacity_set : 1;
   guint builder_visible : 1;
 
+  guint mnemonics_visible : 1;
+  guint mnemonics_visible_set : 1;
+
   GdkWindowTypeHint type_hint;
 
   gdouble opacity;
@@ -230,6 +235,8 @@ static gint gtk_window_client_event   (GtkWidget         *widget,
 static void gtk_window_check_resize       (GtkContainer      *container);
 static gint gtk_window_focus              (GtkWidget        *widget,
                                           GtkDirectionType  direction);
+static void gtk_window_grab_notify        (GtkWidget         *widget,
+                                           gboolean           was_grabbed);
 static void gtk_window_real_set_focus     (GtkWindow         *window,
                                           GtkWidget         *focus);
 
@@ -456,9 +463,9 @@ gtk_window_class_init (GtkWindowClass *klass)
   widget_class->focus_out_event = gtk_window_focus_out_event;
   widget_class->client_event = gtk_window_client_event;
   widget_class->focus = gtk_window_focus;
-  
   widget_class->expose_event = gtk_window_expose;
-   
+  widget_class->grab_notify = gtk_window_grab_notify;
+
   container_class->check_resize = gtk_window_check_resize;
 
   klass->set_focus = gtk_window_real_set_focus;
@@ -591,6 +598,13 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                         P_("Icon for this window"),
                                                         GDK_TYPE_PIXBUF,
                                                         GTK_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                   PROP_MNEMONICS_VISIBLE,
+                                   g_param_spec_boolean ("mnemonics-visible",
+                                                         P_("Mnemonics Visible"),
+                                                         P_("Whether mnemonics are currently visible in this window"),
+                                                         TRUE,
+                                                         GTK_PARAM_READWRITE));
   
   /**
    * GtkWindow:icon-name:
@@ -929,6 +943,7 @@ gtk_window_init (GtkWindow *window)
   priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
   priv->opacity = 1.0;
   priv->startup_id = NULL;
+  priv->mnemonics_visible = TRUE;
 
   colormap = _gtk_widget_peek_colormap ();
   if (colormap)
@@ -951,9 +966,12 @@ gtk_window_set_property (GObject      *object,
                         GParamSpec   *pspec)
 {
   GtkWindow  *window;
+  GtkWindowPrivate *priv;
   
   window = GTK_WINDOW (object);
 
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+
   switch (prop_id)
     {
     case PROP_TYPE:
@@ -1050,6 +1068,9 @@ gtk_window_set_property (GObject      *object,
     case PROP_OPACITY:
       gtk_window_set_opacity (window, g_value_get_double (value));
       break;
+    case PROP_MNEMONICS_VISIBLE:
+      gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1165,6 +1186,9 @@ gtk_window_get_property (GObject      *object,
     case PROP_OPACITY:
       g_value_set_double (value, gtk_window_get_opacity (window));
       break;
+    case PROP_MNEMONICS_VISIBLE:
+      g_value_set_boolean (value, priv->mnemonics_visible);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -4537,6 +4561,7 @@ gtk_window_map (GtkWidget *widget)
   GtkWindow *window = GTK_WINDOW (widget);
   GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
   GdkWindow *toplevel;
+  gboolean auto_mnemonics;
 
   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
 
@@ -4612,6 +4637,14 @@ gtk_window_map (GtkWidget *widget)
           gdk_notify_startup_complete ();
         }
     }
+
+  /* if auto-mnemonics is enabled and mnemonics visible is not already set
+   * (as in the case of popup menus), then hide mnemonics initially
+   */
+  g_object_get (gtk_widget_get_settings (widget), "gtk-auto-mnemonics",
+                &auto_mnemonics, NULL);
+  if (auto_mnemonics && !priv->mnemonics_visible_set)
+    gtk_window_set_mnemonics_visible (window, FALSE);
 }
 
 static gboolean
@@ -5288,10 +5321,18 @@ gtk_window_focus_out_event (GtkWidget     *widget,
                            GdkEventFocus *event)
 {
   GtkWindow *window = GTK_WINDOW (widget);
+  gboolean auto_mnemonics;
 
   _gtk_window_set_has_toplevel_focus (window, FALSE);
   _gtk_window_set_is_active (window, FALSE);
 
+  /* set the mnemonic-visible property to false */
+  g_object_get (gtk_widget_get_settings (widget),
+                "gtk-auto-mnemonics", &auto_mnemonics, NULL);
+  if (auto_mnemonics)
+    gtk_window_set_mnemonics_visible (window, FALSE);
+
+
   return FALSE;
 }
 
@@ -8432,6 +8473,55 @@ gtk_window_get_window_type (GtkWindow *window)
   return window->type;
 }
 
+gboolean
+gtk_window_get_mnemonics_visible (GtkWindow *window)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+
+  return priv->mnemonics_visible;
+}
+
+void
+gtk_window_set_mnemonics_visible (GtkWindow *window,
+                                  gboolean   setting)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+
+  setting = setting != FALSE;
+
+  if (priv->mnemonics_visible != setting)
+    {
+      priv->mnemonics_visible = setting;
+      g_object_notify (G_OBJECT (window), "mnemonics-visible");
+    }
+
+  priv->mnemonics_visible_set = TRUE;
+}
+
+static void
+gtk_window_grab_notify (GtkWidget *widget,
+                        gboolean   was_grabbed)
+{
+  gboolean auto_mnemonics;
+
+  if (was_grabbed)
+    return;
+
+  g_object_get (gtk_widget_get_settings (widget), "gtk-auto-mnemonics",
+                &auto_mnemonics, NULL);
+
+ if (auto_mnemonics)
+   gtk_window_set_mnemonics_visible (GTK_WINDOW (widget), FALSE);
+}
+
 #if defined (G_OS_WIN32) && !defined (_WIN64)
 
 #undef gtk_window_set_icon_from_file
index dc59dfe08ace613fb04ccfccce7947b1ed4361d8..1b4362feaabcc089470ba93ae95aef7c1af573e0 100644 (file)
@@ -230,6 +230,9 @@ gboolean   gtk_window_get_focus_on_map         (GtkWindow           *window);
 void       gtk_window_set_destroy_with_parent  (GtkWindow           *window,
                                                 gboolean             setting);
 gboolean   gtk_window_get_destroy_with_parent  (GtkWindow           *window);
+void       gtk_window_set_mnemonics_visible    (GtkWindow           *window,
+                                                gboolean             setting);
+gboolean   gtk_window_get_mnemonics_visible    (GtkWindow           *window);
 
 void       gtk_window_set_resizable            (GtkWindow           *window,
                                                 gboolean             resizable);